#------以下進行分析與評估資料------#
#---載入套件---#
import pandas as pd #載入pandas套件,命名引用名稱pd
import numpy as np #載入numpy套件,命名引用名稱np
import matplotlib.pyplot as plt #載入matplotlib.pyplot套件,命名引用名稱plt
import seaborn as sns #載入seaborn套件,命名引用名稱sns
import plotly.express as px #載入plotly.express套件,命名引用名稱px
#---讀取檔案---#
data = pd.read_csv(r'C:\Users\shen\Desktop\diabetes.csv') #讀取csv檔,並把資料命名為'data'
data.head(10) #顯示前10筆資料,確認有讀取成功
| Pregnancies | Glucose | BloodPressure | SkinThickness | Insulin | BMI | DiabetesPedigreeFunction | Age | Outcome | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 6 | 148 | 72 | 35 | 0 | 33.6 | 0.627 | 50 | 1 |
| 1 | 1 | 85 | 66 | 29 | 0 | 26.6 | 0.351 | 31 | 0 |
| 2 | 8 | 183 | 64 | 0 | 0 | 23.3 | 0.672 | 32 | 1 |
| 3 | 1 | 89 | 66 | 23 | 94 | 28.1 | 0.167 | 21 | 0 |
| 4 | 0 | 137 | 40 | 35 | 168 | 43.1 | 2.288 | 33 | 1 |
| 5 | 5 | 116 | 74 | 0 | 0 | 25.6 | 0.201 | 30 | 0 |
| 6 | 3 | 78 | 50 | 32 | 88 | 31.0 | 0.248 | 26 | 1 |
| 7 | 10 | 115 | 0 | 0 | 0 | 35.3 | 0.134 | 29 | 0 |
| 8 | 2 | 197 | 70 | 45 | 543 | 30.5 | 0.158 | 53 | 1 |
| 9 | 8 | 125 | 96 | 0 | 0 | 0.0 | 0.232 | 54 | 1 |
#---檢查數據類型---#
data.dtypes #查看資料集內的特徵資料型態
Pregnancies int64 Glucose int64 BloodPressure int64 SkinThickness int64 Insulin int64 BMI float64 DiabetesPedigreeFunction float64 Age int64 Outcome int64 dtype: object
#---查看資料分布筆數---#
Count = data.groupby(["Pregnancies"], as_index=False)["Pregnancies"].agg({"cnt":"count"})
print(Count) #顯示Pregnancies
Count = data.groupby(["Glucose"], as_index=False)["Glucose"].agg({"cnt":"count"})
print(Count) #顯示Glucose
Count = data.groupby(["BloodPressure"], as_index=False)["BloodPressure"].agg({"cnt":"count"})
print(Count) #顯示BloodPressure
Count = data.groupby(["SkinThickness"], as_index=False)["SkinThickness"].agg({"cnt":"count"})
print(Count) #顯示SkinThickness
Count = data.groupby(["Insulin"], as_index=False)["Insulin"].agg({"cnt":"count"})
print(Count) #顯示Insulin
Count = data.groupby(["BMI"], as_index=False)["BMI"].agg({"cnt":"count"})
print(Count) #顯示BMI
Count = data.groupby(["DiabetesPedigreeFunction"], as_index=False)["DiabetesPedigreeFunction"].agg({"cnt":"count"})
print(Count) #顯示DiabetesPedigreeFunction
Count = data.groupby(["Age"], as_index=False)["Age"].agg({"cnt":"count"})
print(Count) #顯示Age
Count = data.groupby(["Outcome"], as_index=False)["Outcome"].agg({"cnt":"count"})
print(Count) #顯示Outcome
Pregnancies cnt
0 0 111
1 1 135
2 2 103
3 3 75
4 4 68
5 5 57
6 6 50
7 7 45
8 8 38
9 9 28
10 10 24
11 11 11
12 12 9
13 13 10
14 14 2
15 15 1
16 17 1
Glucose cnt
0 0 5
1 44 1
2 56 1
3 57 2
4 61 1
.. ... ...
131 195 2
132 196 3
133 197 4
134 198 1
135 199 1
[136 rows x 2 columns]
BloodPressure cnt
0 0 35
1 24 1
2 30 2
3 38 1
4 40 1
5 44 4
6 46 2
7 48 5
8 50 13
9 52 11
10 54 11
11 55 2
12 56 12
13 58 21
14 60 37
15 61 1
16 62 34
17 64 43
18 65 7
19 66 30
20 68 45
21 70 57
22 72 44
23 74 52
24 75 8
25 76 39
26 78 45
27 80 40
28 82 30
29 84 23
30 85 6
31 86 21
32 88 25
33 90 22
34 92 8
35 94 6
36 95 1
37 96 4
38 98 3
39 100 3
40 102 1
41 104 2
42 106 3
43 108 2
44 110 3
45 114 1
46 122 1
SkinThickness cnt
0 0 227
1 7 2
2 8 2
3 10 5
4 11 6
5 12 7
6 13 11
7 14 6
8 15 14
9 16 6
10 17 14
11 18 20
12 19 18
13 20 13
14 21 10
15 22 16
16 23 22
17 24 12
18 25 16
19 26 16
20 27 23
21 28 20
22 29 17
23 30 27
24 31 19
25 32 31
26 33 20
27 34 8
28 35 15
29 36 14
30 37 16
31 38 7
32 39 18
33 40 16
34 41 15
35 42 11
36 43 6
37 44 5
38 45 6
39 46 8
40 47 4
41 48 4
42 49 3
43 50 3
44 51 1
45 52 2
46 54 2
47 56 1
48 60 1
49 63 1
50 99 1
Insulin cnt
0 0 374
1 14 1
2 15 1
3 16 1
4 18 2
.. ... ...
181 579 1
182 600 1
183 680 1
184 744 1
185 846 1
[186 rows x 2 columns]
BMI cnt
0 0.0 11
1 18.2 3
2 18.4 1
3 19.1 1
4 19.3 1
.. ... ...
243 53.2 1
244 55.0 1
245 57.3 1
246 59.4 1
247 67.1 1
[248 rows x 2 columns]
DiabetesPedigreeFunction cnt
0 0.078 1
1 0.084 1
2 0.085 2
3 0.088 2
4 0.089 1
.. ... ...
512 1.893 1
513 2.137 1
514 2.288 1
515 2.329 1
516 2.420 1
[517 rows x 2 columns]
Age cnt
0 21 63
1 22 72
2 23 38
3 24 46
4 25 48
5 26 33
6 27 32
7 28 35
8 29 29
9 30 21
10 31 24
11 32 16
12 33 17
13 34 14
14 35 10
15 36 16
16 37 19
17 38 16
18 39 12
19 40 13
20 41 22
21 42 18
22 43 13
23 44 8
24 45 15
25 46 13
26 47 6
27 48 5
28 49 5
29 50 8
30 51 8
31 52 8
32 53 5
33 54 6
34 55 4
35 56 3
36 57 5
37 58 7
38 59 3
39 60 5
40 61 2
41 62 4
42 63 4
43 64 1
44 65 3
45 66 4
46 67 3
47 68 1
48 69 2
49 70 1
50 72 1
51 81 1
Outcome cnt
0 0 500
1 1 268
#---移除有缺值的欄位---#
columns_to_check = ['Glucose'] #檢查Glucose
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index) #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除
columns_to_check = ['BloodPressure'] #檢查BloodPressure
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index) #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除
columns_to_check = ['SkinThickness'] #檢查SkinThickness
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index) #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除
columns_to_check = ['Insulin'] #檢查Insulin
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index) #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除
columns_to_check = ['BMI'] #檢查BMI
data = data.drop(data.loc[(data[columns_to_check] == 0.0).all(axis=1)].index) #上述項等於0.0表示資料有缺,故如果檢測出某列值等於0.0,則刪除該列,axis=1表示刪除
data = data.reset_index(drop=True) #刪除列資料後,需要reset資料的索引index
#---檢查數值特徵分布---#
data.columns = [col for col in data.columns if data[col].dtype != 'object'] #檢查資料型態不是object的數量
plt.figure(figsize = (20,10))
plot_number = 1
for column in data.columns:
if plot_number <= 14:
ax = plt.subplot(3, 3, plot_number)
sns.histplot(data[column])
plt.xlabel(column)
plot_number +=1
plt.tight_layout()
plt.show()
#---校正資料型態(把資料型態校正回正確的資料型態)---#
data.dtypes #查看整份資料所有欄位資料型態
Pregnancies int64 Glucose int64 BloodPressure int64 SkinThickness int64 Insulin int64 BMI float64 DiabetesPedigreeFunction float64 Age int64 Outcome int64 dtype: object
data.Outcome.unique() #確認預測目標之資料型態為整數(int):1,0
array([0, 1], dtype=int64)
data.head(10) #顯示前10筆資料,確認有刪除成功
| Pregnancies | Glucose | BloodPressure | SkinThickness | Insulin | BMI | DiabetesPedigreeFunction | Age | Outcome | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 89 | 66 | 23 | 94 | 28.1 | 0.167 | 21 | 0 |
| 1 | 0 | 137 | 40 | 35 | 168 | 43.1 | 2.288 | 33 | 1 |
| 2 | 3 | 78 | 50 | 32 | 88 | 31.0 | 0.248 | 26 | 1 |
| 3 | 2 | 197 | 70 | 45 | 543 | 30.5 | 0.158 | 53 | 1 |
| 4 | 1 | 189 | 60 | 23 | 846 | 30.1 | 0.398 | 59 | 1 |
| 5 | 5 | 166 | 72 | 19 | 175 | 25.8 | 0.587 | 51 | 1 |
| 6 | 0 | 118 | 84 | 47 | 230 | 45.8 | 0.551 | 31 | 1 |
| 7 | 1 | 103 | 30 | 38 | 83 | 43.3 | 0.183 | 33 | 0 |
| 8 | 1 | 115 | 70 | 30 | 96 | 34.6 | 0.529 | 32 | 1 |
| 9 | 3 | 126 | 88 | 41 | 235 | 39.3 | 0.704 | 27 | 0 |
#---進行描述性統計,定義畫圖的公式---#
def violin(col): #定義提琴圖,y軸為指定資料欄位,x軸為Outcome,color根據Outcome決定圖形顏色,template表示使用plotly內建的深色主題
fig = px.violin(data, y=col, x="Outcome", color="Outcome", box=True, template = 'plotly_dark')
return fig.show()
def kde(col): #定義分布估計圖,hue參數根據Outcome的欄位進行繪製,height和aspect控制圖形大小和比例,使用map將sns.kdeplot應用到指定資料欄位,並用add_legend在旁附註曲線的分類
grid = sns.FacetGrid(data, hue="Outcome", height = 6, aspect = 2)
grid.map(sns.kdeplot, col)
grid.add_legend()
def scatter(col1, col2): #繪製散布圖,x軸為指定欄位col1,y軸為指定欄位col2,color根據Outcome決定圖形顏色,template表示使用plotly內建的深色主題
fig = px.scatter(data, x= col1, y=col2, color="Outcome", template = 'plotly_dark')
return fig.show()
violin('Glucose')
violin('SkinThickness')
violin('Insulin')
violin('BMI')
violin('Age')
kde('Glucose')
kde('Insulin')
kde('Age')
scatter('Glucose', 'Insulin')
scatter('Glucose', 'DiabetesPedigreeFunction')
scatter('Glucose', 'BMI')
scatter('SkinThickness', 'BMI')
#根據提琴圖、分布估計圖、散布圖針對Glucose的分析可以發現,當Glucose數值低於120,沒有得糖尿病的人占多數。
#根據提琴圖、分布估計圖、散步圖針對Insulin的分析可以發現,當Insulin數值約90時,沒有患糖尿病的人占多數,而當Insulin數值開始高於160後,患有糖尿病的人就逐漸增加
#根據提琴圖、分布估計圖、散步圖針對Age的分析可以發現,年齡越大的人患有糖尿病的人越多
#---採用One-hot-encoding編碼方式,轉換成數值型態,使模型能夠使用可量化的資料---#
data_one_hot = pd.get_dummies(data)
data_one_hot.head(10)
| Pregnancies | Glucose | BloodPressure | SkinThickness | Insulin | BMI | DiabetesPedigreeFunction | Age | Outcome | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 89 | 66 | 23 | 94 | 28.1 | 0.167 | 21 | 0 |
| 1 | 0 | 137 | 40 | 35 | 168 | 43.1 | 2.288 | 33 | 1 |
| 2 | 3 | 78 | 50 | 32 | 88 | 31.0 | 0.248 | 26 | 1 |
| 3 | 2 | 197 | 70 | 45 | 543 | 30.5 | 0.158 | 53 | 1 |
| 4 | 1 | 189 | 60 | 23 | 846 | 30.1 | 0.398 | 59 | 1 |
| 5 | 5 | 166 | 72 | 19 | 175 | 25.8 | 0.587 | 51 | 1 |
| 6 | 0 | 118 | 84 | 47 | 230 | 45.8 | 0.551 | 31 | 1 |
| 7 | 1 | 103 | 30 | 38 | 83 | 43.3 | 0.183 | 33 | 0 |
| 8 | 1 | 115 | 70 | 30 | 96 | 34.6 | 0.529 | 32 | 1 |
| 9 | 3 | 126 | 88 | 41 | 235 | 39.3 | 0.704 | 27 | 0 |
#---區分特徵欄位和預測目標欄位---#
clear_data = data_one_hot.drop(['Outcome'],axis=1) #用drop和axis=1將Outcome這個欄位移除,並將剩餘欄位命名為 clear_data(特徵欄位)
label = data_one_hot['Outcome'] #將Outcome欄位命名為 label(預測目標欄位),因為這是要預測的,所以不能放在特徵資料中
clear_data.head() #顯示前5筆資料,確認有刪除成功
| Pregnancies | Glucose | BloodPressure | SkinThickness | Insulin | BMI | DiabetesPedigreeFunction | Age | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 89 | 66 | 23 | 94 | 28.1 | 0.167 | 21 |
| 1 | 0 | 137 | 40 | 35 | 168 | 43.1 | 2.288 | 33 |
| 2 | 3 | 78 | 50 | 32 | 88 | 31.0 | 0.248 | 26 |
| 3 | 2 | 197 | 70 | 45 | 543 | 30.5 | 0.158 | 53 |
| 4 | 1 | 189 | 60 | 23 | 846 | 30.1 | 0.398 | 59 |
#-----以下進行模型開發-----#
# 將資料分成輸入特徵 (x_features) 和輸出標籤 (y_label)
x_features = data_one_hot.iloc[:,:-1]
y_label = data_one_hot.iloc[:,-1]
x_features
| Pregnancies | Glucose | BloodPressure | SkinThickness | Insulin | BMI | DiabetesPedigreeFunction | Age | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 89 | 66 | 23 | 94 | 28.1 | 0.167 | 21 |
| 1 | 0 | 137 | 40 | 35 | 168 | 43.1 | 2.288 | 33 |
| 2 | 3 | 78 | 50 | 32 | 88 | 31.0 | 0.248 | 26 |
| 3 | 2 | 197 | 70 | 45 | 543 | 30.5 | 0.158 | 53 |
| 4 | 1 | 189 | 60 | 23 | 846 | 30.1 | 0.398 | 59 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 387 | 0 | 181 | 88 | 44 | 510 | 43.3 | 0.222 | 26 |
| 388 | 1 | 128 | 88 | 39 | 110 | 36.5 | 1.057 | 37 |
| 389 | 2 | 88 | 58 | 26 | 16 | 28.4 | 0.766 | 22 |
| 390 | 10 | 101 | 76 | 48 | 180 | 32.9 | 0.171 | 63 |
| 391 | 5 | 121 | 72 | 23 | 112 | 26.2 | 0.245 | 30 |
392 rows × 8 columns
#---切分資料集---#
from sklearn.model_selection import KFold #導入KFold類別,將數據集劃分為k個子集,每個子集均做一次驗證,其餘k-1個子集則用於訓練
kf = KFold(n_splits=5, shuffle=True, random_state=27) #創建物件實例kf,n_splits指定將數據集分為5個子集,shuffle指定是否對數據集進行洗牌,減少數據集中的偏差,random_state指定隨機種子
#---選擇模型---#
#導入線性回歸模型
from sklearn.linear_model import LinearRegression
model = LinearRegression()
#---交叉驗證---#
#建立四個空的列表,用來記錄模型訓練和驗證的結果
test_bias = []
test_variance = []
train_errors = []
test_errors = []
#利用K-Fold交叉驗證來評估模型的表現
for train_index, test_index in kf.split(x_features):
# 將資料分成訓練集和測試集
X_train, y_train = x_features.iloc[train_index], y_label[train_index]
X_test, y_test = x_features.iloc[test_index], y_label[test_index]
#使用訓練數據來訓練模型
model.fit(X_train, y_train)
#使用模型對訓練集和測試集進行預測
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
#計算測試集的偏差和方差
bias = np.sum((y_test_pred - np.mean(y_test)) ** 2) / len(y_test_pred)
variance = np.sum((y_test_pred - np.mean(y_test_pred)) ** 2) / len(y_test_pred)
bias_2 = np.mean((y_test_pred - np.mean(y_test)) ** 2)
variance_2 = np.var(y_test_pred)
#將偏差和方差加入對應的列表中
test_bias.append(bias)
test_variance.append(variance)
#計算訓練集和測試集的誤差並加入對應的列表中
train_error = np.sum((y_train_pred - y_train) ** 2) /len(y_train_pred)
test_error = np.sum((y_test_pred - y_test) ** 2) / len(y_test_pred)
train_errors.append(train_error)
test_errors.append(test_error)
#輸出偏差、方差、訓練誤差和測試誤差的平均值
print("Bias:",test_bias)
print("Variance:",test_variance)
print("平均訓練誤差:",sum(train_errors) / len(train_errors))
print("平均測試誤差:",sum(test_errors) / len(test_errors))
Bias: [0.06173376533192481, 0.07961531160219776, 0.07808017943498077, 0.08517315354396755, 0.09628003143551711] Variance: [0.06039590930525523, 0.0773451895216898, 0.07613999536379225, 0.08273076794601372, 0.09605606082614357] 平均訓練誤差: 0.1443805607948426 平均測試誤差: 0.15072123674344412